import datetime
import time
import calendar
import pytz
import pandas as pd
from typing import List
from datetime import datetime as dt, timedelta
from dateutil.relativedelta import relativedelta
from typing import Tuple


def str2datetime(datetime_str, date_format='%Y-%m-%d %H:%M:%S'):
    """
    日期字符串转换成日期
    :param datetime_str: 日期字符串
    :param date_format: 日期格式
    :return: 日期
    """
    if datetime_str:
        return datetime.datetime.strptime(datetime_str, date_format)
    return None


def datetime2str(date_time, date_format='%Y-%m-%d %H:%M:%S'):
    """
    日期转换成字符串
    :param date_time: 日期
    :param date_format: 日期格式
    :return: 日期字符串
    """
    if date_time:
        return date_time.strftime(date_format)
    return None


def datetime2timestamp(date_time):
    """
    日期转换成时间戳
    :param date_time: 日期
    :return: 时间戳
    """
    if date_time:
        return time.mktime(time.strptime(date_time.strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S'))
    return None


def timestamp2datetime(timestamp):
    """
    时间戳转换成日期
    :param timestamp: 时间戳
    :return: 日期
    """
    if timestamp:
        return datetime.datetime.strptime(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)),
                                          '%Y-%m-%d %H:%M:%S')
    return None


def timestamp2str(timestamp, date_format='%Y-%m-%d %H:%M:%S'):
    """
    时间戳转换成字符串
    :param timestamp:
    :param date_format:
    :return:
    """
    if timestamp:
        return datetime2str(timestamp2datetime(timestamp), date_format)
    return None


def str2timestamp(datetime_str, date_format='%Y-%m-%d %H:%M:%S'):
    """
    字符串转换成时间戳
    :param datetime_str:
    :param date_format:
    :return:
    """
    if datetime_str:
        return datetime2timestamp(str2datetime(datetime_str, date_format))
    return None


config = {}


def get_location_time(add_hours=0,
                      add_days=0, add_minutes=0):
    """
    获取本地时间，按照需求可以添加时间差
    如有需要可配置config里面的def_time_zone为你想要的时区

    :param add_hours:
    :param add_days:
    :param add_minutes: 要相加的时差
    :return: datetime, 带时区的时间
    """
    time_zone = config.get('def_time_zone', 'Asia/Shanghai')
    try:
        now_time = dt.now(tz=pytz.timezone(time_zone))
    except:
        tz = 'Asia/Shanghai'
        now_time = dt.now(tz=pytz.timezone(tz))
    if add_hours != 0:
        now_time = now_time + timedelta(hours=add_hours)
    if add_days != 0:
        now_time = now_time + timedelta(days=add_days)
    if add_minutes != 0:
        now_time = now_time + timedelta(minutes=add_minutes)
    return now_time


def get_zero_today(date_time: datetime.datetime):
    """
    获取今日0时0分0秒
    :param date_time:
    :param date_format:
    :return: <class 'datetime.datetime'>
    """
    if isinstance(date_time, datetime.datetime):
        zero_today = date_time - timedelta(hours=date_time.hour, minutes=date_time.minute, seconds=date_time.second,
                                           microseconds=date_time.microsecond)
        return zero_today
    return None


def get_last_today(date_time: datetime.datetime):
    """
    获取今日23时59分59秒
    :param date_time:
    :return: <class 'datetime.datetime'>
    """
    if isinstance(date_time, datetime.datetime):
        last_today = get_zero_today(date_time) + timedelta(hours=23, minutes=59, seconds=59)
        return last_today
    return None


def get_day_forward_zero(date_time: datetime.datetime, day: int):
    """
    获取几天前的0点0分0秒
    :param date_time: datetime.datetime类型
    :param day: 整数类型，近n天时，day传入值为n-1
    :return:
    """
    if isinstance(date_time, datetime.datetime) and isinstance(day, int):
        delta = timedelta(days=day)
        n_days_forward_zero = get_zero_today(date_time) - delta
        return n_days_forward_zero
    return None


def get_weekdays(date_str: str):
    """
    判断今天星期几
    :param date_str: dt.today().strftime("%Y-%m-%d")
    :return: str
    """
    week_list = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
    week_index = time.strptime(date_str, '%Y-%m-%d').tm_wday  # 获取指定时间的星期
    week = week_list[week_index]
    return week


def get_lately_day(day: int) -> List[str]:
    """
    获取近几天的列表：['2022-10-15', '2022-10-16', '2022-10-17', '2022-10-18', '2022-10-19']
    """

    def _get_date_range(start: datetime, end: datetime) -> List[str]:
        ret = []
        while start < end:
            ret.append(start.strftime("%Y-%m-%d"))
            start += datetime.timedelta(days=1)
        return ret

    tomorrow = datetime.datetime.now() + datetime.timedelta(days=1)
    a_week_ago = (tomorrow - datetime.timedelta(days=day)
                  ).replace(hour=23, minute=59, second=59)
    date_range = _get_date_range(a_week_ago, tomorrow)
    return date_range


def get_date_of_month(form="%Y-%m-%d"):
    """
    获取本月开始结束日期
    :param form 返回值显示格式
    :return: str，date tuple
    """
    today = get_location_time().date()
    year = today.year
    month = today.month
    begin_of_month = datetime.date(year, month, 1).strftime(form)
    _, day = calendar.monthrange(year, month)
    end_of_month = datetime.date(year, month, day).strftime(form)
    return begin_of_month, end_of_month


def get_date_of_last_month(form="%Y-%m-%d"):
    """
    获取上月开始结束日期
    :param form 返回值显示格式
    :return: str，date tuple
    """
    today = get_location_time().today()
    end_of_last_month = today - datetime.timedelta(today.day)
    begin_of_last_month = datetime.date(end_of_last_month.year, end_of_last_month.month, 1)
    return begin_of_last_month.strftime(form), end_of_last_month.strftime(form)


def day_last_mn(today: datetime):
    """
    获取上个月的今天
    """
    endDayOfLastMonth = today - relativedelta(months=1)
    return dt.strftime(endDayOfLastMonth, "%Y-%m-%d")


import arrow


def get_year(num):
    """
    近n年的年份日期
    """
    year_list = []
    a = arrow.now()  # 当前本地时间
    for i in range(0, num + 1):
        year = a.shift(years=-i).format("YYYY")
        year_list.append(year)
    return year_list


def get_today_time_range():
    """
    获取今天时间段，如['2023-09-15 00:00:00' ,'2023-09-15 01:00:00']
    """
    now = get_location_time().now()
    today = now.strftime('%Y-%m-%d')
    return pd.date_range(today, periods=24, freq='H').strftime('%Y-%m-%d %H:%M:%S').tolist()


def get_quarter_start_end_date() -> Tuple[datetime.datetime, datetime.datetime]:
    # 获取当前季度的开始时间和结束时间
    now = datetime.datetime.now()
    quarter_start = datetime.datetime(now.year, (now.month - 1) // 3 * 3 + 1, 1)
    quarter_end = datetime.datetime(now.year, (now.month - 1) // 3 * 3 + 3, 1)
    return quarter_start, quarter_end


if __name__ == '__main__':
    print(get_quarter_start_end_date())

# if __name__ == '__main__':
# print(get_location_time())  # 2022-09-15 10:29:15.231725+08:00
#
# datetime_str = '2022-09-15 10:29:15'  # <class 'str'>
#
# print(str2datetime(datetime_str))  # 2022-09-15 10:29:15
# print(type(str2datetime(datetime_str)))  # <class 'datetime.datetime'>
#
# datetime_datetime = str2datetime(datetime_str)  # <class 'datetime.datetime'>
# print(datetime2str(datetime_datetime))  # 2022-09-15 10:29:15
# print(type(datetime2str(datetime_datetime)))  # <class 'str'>
#
# sjc_datetime = datetime2timestamp(datetime_datetime)
# print(datetime2timestamp(datetime_datetime))  # 1663208955.0
# print(type(datetime2timestamp(datetime_datetime)))  # <class 'float'>
#
# print(timestamp2datetime(sjc_datetime))  # 2022-09-15 10:29:15
# print(type(timestamp2datetime(sjc_datetime)))  # <class 'datetime.datetime'>
#
# print(timestamp2str(sjc_datetime))  # 2022-09-15 10:29:15
# print(type(timestamp2str(sjc_datetime)))  # <class 'str'>
#
# str_datetime = timestamp2str(sjc_datetime)  # <class 'str'>
# print(str2timestamp(str_datetime))  # 1663208955.0
# print(type(str2timestamp(str_datetime)))  # <class 'float'>
# print(get_date_of_month())
# print(get_date_of_last_month())
#
# print(get_location_time().strftime('%Y-%m-%d %H:%M'))
# print(dt.strptime(get_location_time().strftime('%Y-%m-%d'), "%Y-%m-%d").today())

# now = get_location_time().strftime("%Y-%m-%d")
# statistics_date = datetime.datetime.strptime(now, "%Y-%m-%d").today()
# mouth = statistics_date.month
# day = statistics_date.day

# print(f'\033[1;35m{day_last_mn(statistics_date)}\033[0m')
# print(f'\033[1;35m{statistics_date}\033[0m')
# print(f'\033[1;35m{type(statistics_date)}\033[0m')

# print(f'\033[1;35m{get_location_time().date().strftime("%Y-%m-%d")}\033[0m')
# print(f'\033[1;35m{type(get_location_time())}\033[0m')
#
# print(f'\033[1;35m{get_date_of_month()}\033[0m')
